/**
 * 聲明類型，優化代碼
 */
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import Stats from 'three/addons/libs/stats.module.js';
import { ActionType, Msg } from './Msg';

let canvas = document.getElementById("canvas") as HTMLCanvasElement;
let stage = new THREE.Object3D();

let boxList: THREE.Mesh[] = [];
let sphereList: THREE.Mesh[] = [];
let plane: THREE.Mesh;

let camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.z = 20;

let scene = new THREE.Scene();
scene.add(stage);

let renderer = new THREE.WebGLRenderer({ antialias: true, canvas });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = false;
// renderer.shadowMap.type = THREE.PCFSoftShadowMap; // default THREE.PCFShadowMap

let stats = new Stats();
document.body.appendChild(stats.dom);

const controls = new OrbitControls(camera, renderer.domElement);
controls.minDistance = 1;
controls.maxDistance = 1000;
controls.update();

const worker = new Worker(new URL('./worker.ts', import.meta.url), {
    type: 'module',
});

addViews();
animate();

function addViews() {
    const size = { width: 1, height: 1, depth: 1 };
    const total = 1000;
    const r = 1;

    const boxGeometry = new THREE.BoxGeometry(size.width, size.height, size.depth);
    const boxMaterial = new THREE.MeshNormalMaterial();
    const boxOne = new THREE.Mesh(boxGeometry, boxMaterial);

    for (let i = 0; i < total; i++) {
        const box = boxOne.clone();
        stage.add(box);
        boxList.push(box);
    }

    const sphereGeometry = new THREE.SphereGeometry(r);
    const sphereMaterial = new THREE.MeshNormalMaterial();
    const sphereOne = new THREE.Mesh(sphereGeometry, sphereMaterial);

    for (let i = 0; i < total; i++) {
        const sphere = sphereOne.clone();
        stage.add(sphere);
        sphereList.push(sphere);
    }

    const planeGeometry = new THREE.PlaneGeometry(10, 10, 1, 1);
    const planeMaterial = new THREE.MeshNormalMaterial();
    plane = new THREE.Mesh(planeGeometry, planeMaterial);
    stage.add(plane);

    worker.postMessage(new Msg(ActionType.Init, {
        box: { t: total, size },
        sphere: { t: total, r }
    }))

    worker.onmessage = (e) => {
        let { action, data } = e.data as Msg;
        if (action == ActionType.Update) {
            let { planeData, sphereData, boxData } = data;
            plane.position.set(planeData.p.x, planeData.p.y, planeData.p.z);
            plane.quaternion.set(planeData.q.x, planeData.q.y, planeData.q.z, planeData.q.w);
            boxList.forEach((box, i) => {
                if (!boxData[i]) return;
                let p = boxData[i].p;
                let q = boxData[i].q;
                box.position.set(p.x, p.y, p.z);
                box.quaternion.set(q.x, q.y, q.z, q.w);
            });
            sphereList.forEach((sphere, i) => {
                if (!sphereData[i]) return;
                let p = sphereData[i].p;
                let q = sphereData[i].q;
                sphere.position.set(p.x, p.y, p.z);
                sphere.quaternion.set(q.x, q.y, q.z, q.w);
            });
        }
    }

}

function animate() {
    stats.update();
    renderer.render(scene, camera);
    requestAnimationFrame(animate);
}
